1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 /**********************************************************************
27 **********************************************************************
28 **********************************************************************
29 *** COPYRIGHT (c) Eastman Kodak Company, 1997 ***
30 *** As an unpublished work pursuant to Title 17 of the United ***
31 *** States Code. All rights reserved. ***
32 **********************************************************************
33 **********************************************************************
34 **********************************************************************/
35
36 package java.awt.color;
37
38 import sun.java2d.cmm.PCMM;
39 import sun.java2d.cmm.CMSManager;
40 import sun.java2d.cmm.ProfileDeferralMgr;
41 import sun.java2d.cmm.ProfileDeferralInfo;
42 import sun.java2d.cmm.ProfileActivator;
43
44 import java.io.File;
45 import java.io.FileInputStream;
46 import java.io.FileNotFoundException;
47 import java.io.FileOutputStream;
48 import java.io.IOException;
49 import java.io.InputStream;
50 import java.io.ObjectInputStream;
51 import java.io.ObjectOutputStream;
52 import java.io.ObjectStreamException;
53 import java.io.OutputStream;
54 import java.io.Serializable;
55
56 import java.util.StringTokenizer;
57
58 import java.security.AccessController;
59 import java.security.PrivilegedAction;
60
61
62 /**
63 * A representation of color profile data for device independent and
64 * device dependent color spaces based on the International Color
65 * Consortium Specification ICC.1:2001-12, File Format for Color Profiles,
66 * (see <A href="http://www.color.org"> http://www.color.org</A>).
67 * <p>
68 * An ICC_ColorSpace object can be constructed from an appropriate
69 * ICC_Profile.
70 * Typically, an ICC_ColorSpace would be associated with an ICC
71 * Profile which is either an input, display, or output profile (see
72 * the ICC specification). There are also device link, abstract,
73 * color space conversion, and named color profiles. These are less
74 * useful for tagging a color or image, but are useful for other
75 * purposes (in particular device link profiles can provide improved
76 * performance for converting from one device's color space to
77 * another's).
78 * <p>
79 * ICC Profiles represent transformations from the color space of
80 * the profile (e.g. a monitor) to a Profile Connection Space (PCS).
81 * Profiles of interest for tagging images or colors have a PCS
82 * which is one of the two specific device independent
83 * spaces (one CIEXYZ space and one CIELab space) defined in the
84 * ICC Profile Format Specification. Most profiles of interest
85 * either have invertible transformations or explicitly specify
86 * transformations going both directions.
87 * <p>
88 * @see ICC_ColorSpace
89 */
90
91
92 public class ICC_Profile implements Serializable {
93
94 private static final long serialVersionUID = -3938515861990936766L;
95
96 transient long ID;
97
98 private transient ProfileDeferralInfo deferralInfo;
99 private transient ProfileActivator profileActivator;
100
101 // Registry of singleton profile objects for specific color spaces
102 // defined in the ColorSpace class (e.g. CS_sRGB), see
103 // getInstance(int cspace) factory method.
104 private static ICC_Profile sRGBprofile;
105 private static ICC_Profile XYZprofile;
106 private static ICC_Profile PYCCprofile;
107 private static ICC_Profile GRAYprofile;
108 private static ICC_Profile LINEAR_RGBprofile;
109
110
111 /**
112 * Profile class is input.
113 */
114 public static final int CLASS_INPUT = 0;
115
116 /**
117 * Profile class is display.
118 */
119 public static final int CLASS_DISPLAY = 1;
120
121 /**
122 * Profile class is output.
123 */
124 public static final int CLASS_OUTPUT = 2;
125
126 /**
127 * Profile class is device link.
128 */
129 public static final int CLASS_DEVICELINK = 3;
130
131 /**
132 * Profile class is color space conversion.
133 */
134 public static final int CLASS_COLORSPACECONVERSION = 4;
135
136 /**
137 * Profile class is abstract.
138 */
139 public static final int CLASS_ABSTRACT = 5;
140
141 /**
142 * Profile class is named color.
143 */
144 public static final int CLASS_NAMEDCOLOR = 6;
145
146
147 /**
148 * ICC Profile Color Space Type Signature: 'XYZ '.
149 */
150 public static final int icSigXYZData = 0x58595A20; /* 'XYZ ' */
151
152 /**
153 * ICC Profile Color Space Type Signature: 'Lab '.
154 */
155 public static final int icSigLabData = 0x4C616220; /* 'Lab ' */
156
157 /**
158 * ICC Profile Color Space Type Signature: 'Luv '.
159 */
160 public static final int icSigLuvData = 0x4C757620; /* 'Luv ' */
161
162 /**
163 * ICC Profile Color Space Type Signature: 'YCbr'.
164 */
165 public static final int icSigYCbCrData = 0x59436272; /* 'YCbr' */
166
167 /**
168 * ICC Profile Color Space Type Signature: 'Yxy '.
169 */
170 public static final int icSigYxyData = 0x59787920; /* 'Yxy ' */
171
172 /**
173 * ICC Profile Color Space Type Signature: 'RGB '.
174 */
175 public static final int icSigRgbData = 0x52474220; /* 'RGB ' */
176
177 /**
178 * ICC Profile Color Space Type Signature: 'GRAY'.
179 */
180 public static final int icSigGrayData = 0x47524159; /* 'GRAY' */
181
182 /**
183 * ICC Profile Color Space Type Signature: 'HSV'.
184 */
185 public static final int icSigHsvData = 0x48535620; /* 'HSV ' */
186
187 /**
188 * ICC Profile Color Space Type Signature: 'HLS'.
189 */
190 public static final int icSigHlsData = 0x484C5320; /* 'HLS ' */
191
192 /**
193 * ICC Profile Color Space Type Signature: 'CMYK'.
194 */
195 public static final int icSigCmykData = 0x434D594B; /* 'CMYK' */
196
197 /**
198 * ICC Profile Color Space Type Signature: 'CMY '.
199 */
200 public static final int icSigCmyData = 0x434D5920; /* 'CMY ' */
201
202 /**
203 * ICC Profile Color Space Type Signature: '2CLR'.
204 */
205 public static final int icSigSpace2CLR = 0x32434C52; /* '2CLR' */
206
207 /**
208 * ICC Profile Color Space Type Signature: '3CLR'.
209 */
210 public static final int icSigSpace3CLR = 0x33434C52; /* '3CLR' */
211
212 /**
213 * ICC Profile Color Space Type Signature: '4CLR'.
214 */
215 public static final int icSigSpace4CLR = 0x34434C52; /* '4CLR' */
216
217 /**
218 * ICC Profile Color Space Type Signature: '5CLR'.
219 */
220 public static final int icSigSpace5CLR = 0x35434C52; /* '5CLR' */
221
222 /**
223 * ICC Profile Color Space Type Signature: '6CLR'.
224 */
225 public static final int icSigSpace6CLR = 0x36434C52; /* '6CLR' */
226
227 /**
228 * ICC Profile Color Space Type Signature: '7CLR'.
229 */
230 public static final int icSigSpace7CLR = 0x37434C52; /* '7CLR' */
231
232 /**
233 * ICC Profile Color Space Type Signature: '8CLR'.
234 */
235 public static final int icSigSpace8CLR = 0x38434C52; /* '8CLR' */
236
237 /**
238 * ICC Profile Color Space Type Signature: '9CLR'.
239 */
240 public static final int icSigSpace9CLR = 0x39434C52; /* '9CLR' */
241
242 /**
243 * ICC Profile Color Space Type Signature: 'ACLR'.
244 */
245 public static final int icSigSpaceACLR = 0x41434C52; /* 'ACLR' */
246
247 /**
248 * ICC Profile Color Space Type Signature: 'BCLR'.
249 */
250 public static final int icSigSpaceBCLR = 0x42434C52; /* 'BCLR' */
251
252 /**
253 * ICC Profile Color Space Type Signature: 'CCLR'.
254 */
255 public static final int icSigSpaceCCLR = 0x43434C52; /* 'CCLR' */
256
257 /**
258 * ICC Profile Color Space Type Signature: 'DCLR'.
259 */
260 public static final int icSigSpaceDCLR = 0x44434C52; /* 'DCLR' */
261
262 /**
263 * ICC Profile Color Space Type Signature: 'ECLR'.
264 */
265 public static final int icSigSpaceECLR = 0x45434C52; /* 'ECLR' */
266
267 /**
268 * ICC Profile Color Space Type Signature: 'FCLR'.
269 */
270 public static final int icSigSpaceFCLR = 0x46434C52; /* 'FCLR' */
271
272
273 /**
274 * ICC Profile Class Signature: 'scnr'.
275 */
276 public static final int icSigInputClass = 0x73636E72; /* 'scnr' */
277
278 /**
279 * ICC Profile Class Signature: 'mntr'.
280 */
281 public static final int icSigDisplayClass = 0x6D6E7472; /* 'mntr' */
282
283 /**
284 * ICC Profile Class Signature: 'prtr'.
285 */
286 public static final int icSigOutputClass = 0x70727472; /* 'prtr' */
287
288 /**
289 * ICC Profile Class Signature: 'link'.
290 */
291 public static final int icSigLinkClass = 0x6C696E6B; /* 'link' */
292
293 /**
294 * ICC Profile Class Signature: 'abst'.
295 */
296 public static final int icSigAbstractClass = 0x61627374; /* 'abst' */
297
298 /**
299 * ICC Profile Class Signature: 'spac'.
300 */
301 public static final int icSigColorSpaceClass = 0x73706163; /* 'spac' */
302
303 /**
304 * ICC Profile Class Signature: 'nmcl'.
305 */
306 public static final int icSigNamedColorClass = 0x6e6d636c; /* 'nmcl' */
307
308
309 /**
310 * ICC Profile Rendering Intent: Perceptual.
311 */
312 public static final int icPerceptual = 0;
313
314 /**
315 * ICC Profile Rendering Intent: RelativeColorimetric.
316 */
317 public static final int icRelativeColorimetric = 1;
318
319 /**
320 * ICC Profile Rendering Intent: Media-RelativeColorimetric.
321 * @since 1.5
322 */
323 public static final int icMediaRelativeColorimetric = 1;
324
325 /**
326 * ICC Profile Rendering Intent: Saturation.
327 */
328 public static final int icSaturation = 2;
329
330 /**
331 * ICC Profile Rendering Intent: AbsoluteColorimetric.
332 */
333 public static final int icAbsoluteColorimetric = 3;
334
335 /**
336 * ICC Profile Rendering Intent: ICC-AbsoluteColorimetric.
337 * @since 1.5
338 */
339 public static final int icICCAbsoluteColorimetric = 3;
340
341
342 /**
343 * ICC Profile Tag Signature: 'head' - special.
344 */
345 public static final int icSigHead = 0x68656164; /* 'head' - special */
346
347 /**
348 * ICC Profile Tag Signature: 'A2B0'.
349 */
350 public static final int icSigAToB0Tag = 0x41324230; /* 'A2B0' */
351
352 /**
353 * ICC Profile Tag Signature: 'A2B1'.
354 */
355 public static final int icSigAToB1Tag = 0x41324231; /* 'A2B1' */
356
357 /**
358 * ICC Profile Tag Signature: 'A2B2'.
359 */
360 public static final int icSigAToB2Tag = 0x41324232; /* 'A2B2' */
361
362 /**
363 * ICC Profile Tag Signature: 'bXYZ'.
364 */
365 public static final int icSigBlueColorantTag = 0x6258595A; /* 'bXYZ' */
366
367 /**
368 * ICC Profile Tag Signature: 'bXYZ'.
369 * @since 1.5
370 */
371 public static final int icSigBlueMatrixColumnTag = 0x6258595A; /* 'bXYZ' */
372
373 /**
374 * ICC Profile Tag Signature: 'bTRC'.
375 */
376 public static final int icSigBlueTRCTag = 0x62545243; /* 'bTRC' */
377
378 /**
379 * ICC Profile Tag Signature: 'B2A0'.
380 */
381 public static final int icSigBToA0Tag = 0x42324130; /* 'B2A0' */
382
383 /**
384 * ICC Profile Tag Signature: 'B2A1'.
385 */
386 public static final int icSigBToA1Tag = 0x42324131; /* 'B2A1' */
387
388 /**
389 * ICC Profile Tag Signature: 'B2A2'.
390 */
391 public static final int icSigBToA2Tag = 0x42324132; /* 'B2A2' */
392
393 /**
394 * ICC Profile Tag Signature: 'calt'.
395 */
396 public static final int icSigCalibrationDateTimeTag = 0x63616C74;
397 /* 'calt' */
398
399 /**
400 * ICC Profile Tag Signature: 'targ'.
401 */
402 public static final int icSigCharTargetTag = 0x74617267; /* 'targ' */
403
404 /**
405 * ICC Profile Tag Signature: 'cprt'.
406 */
407 public static final int icSigCopyrightTag = 0x63707274; /* 'cprt' */
408
409 /**
410 * ICC Profile Tag Signature: 'crdi'.
411 */
412 public static final int icSigCrdInfoTag = 0x63726469; /* 'crdi' */
413
414 /**
415 * ICC Profile Tag Signature: 'dmnd'.
416 */
417 public static final int icSigDeviceMfgDescTag = 0x646D6E64; /* 'dmnd' */
418
419 /**
420 * ICC Profile Tag Signature: 'dmdd'.
421 */
422 public static final int icSigDeviceModelDescTag = 0x646D6464; /* 'dmdd' */
423
424 /**
425 * ICC Profile Tag Signature: 'devs'.
426 */
427 public static final int icSigDeviceSettingsTag = 0x64657673; /* 'devs' */
428
429 /**
430 * ICC Profile Tag Signature: 'gamt'.
431 */
432 public static final int icSigGamutTag = 0x67616D74; /* 'gamt' */
433
434 /**
435 * ICC Profile Tag Signature: 'kTRC'.
436 */
437 public static final int icSigGrayTRCTag = 0x6b545243; /* 'kTRC' */
438
439 /**
440 * ICC Profile Tag Signature: 'gXYZ'.
441 */
442 public static final int icSigGreenColorantTag = 0x6758595A; /* 'gXYZ' */
443
444 /**
445 * ICC Profile Tag Signature: 'gXYZ'.
446 * @since 1.5
447 */
448 public static final int icSigGreenMatrixColumnTag = 0x6758595A;/* 'gXYZ' */
449
450 /**
451 * ICC Profile Tag Signature: 'gTRC'.
452 */
453 public static final int icSigGreenTRCTag = 0x67545243; /* 'gTRC' */
454
455 /**
456 * ICC Profile Tag Signature: 'lumi'.
457 */
458 public static final int icSigLuminanceTag = 0x6C756d69; /* 'lumi' */
459
460 /**
461 * ICC Profile Tag Signature: 'meas'.
462 */
463 public static final int icSigMeasurementTag = 0x6D656173; /* 'meas' */
464
465 /**
466 * ICC Profile Tag Signature: 'bkpt'.
467 */
468 public static final int icSigMediaBlackPointTag = 0x626B7074; /* 'bkpt' */
469
470 /**
471 * ICC Profile Tag Signature: 'wtpt'.
472 */
473 public static final int icSigMediaWhitePointTag = 0x77747074; /* 'wtpt' */
474
475 /**
476 * ICC Profile Tag Signature: 'ncl2'.
477 */
478 public static final int icSigNamedColor2Tag = 0x6E636C32; /* 'ncl2' */
479
480 /**
481 * ICC Profile Tag Signature: 'resp'.
482 */
483 public static final int icSigOutputResponseTag = 0x72657370; /* 'resp' */
484
485 /**
486 * ICC Profile Tag Signature: 'pre0'.
487 */
488 public static final int icSigPreview0Tag = 0x70726530; /* 'pre0' */
489
490 /**
491 * ICC Profile Tag Signature: 'pre1'.
492 */
493 public static final int icSigPreview1Tag = 0x70726531; /* 'pre1' */
494
495 /**
496 * ICC Profile Tag Signature: 'pre2'.
497 */
498 public static final int icSigPreview2Tag = 0x70726532; /* 'pre2' */
499
500 /**
501 * ICC Profile Tag Signature: 'desc'.
502 */
503 public static final int icSigProfileDescriptionTag = 0x64657363;
504 /* 'desc' */
505
506 /**
507 * ICC Profile Tag Signature: 'pseq'.
508 */
509 public static final int icSigProfileSequenceDescTag = 0x70736571;
510 /* 'pseq' */
511
512 /**
513 * ICC Profile Tag Signature: 'psd0'.
514 */
515 public static final int icSigPs2CRD0Tag = 0x70736430; /* 'psd0' */
516
517 /**
518 * ICC Profile Tag Signature: 'psd1'.
519 */
520 public static final int icSigPs2CRD1Tag = 0x70736431; /* 'psd1' */
521
522 /**
523 * ICC Profile Tag Signature: 'psd2'.
524 */
525 public static final int icSigPs2CRD2Tag = 0x70736432; /* 'psd2' */
526
527 /**
528 * ICC Profile Tag Signature: 'psd3'.
529 */
530 public static final int icSigPs2CRD3Tag = 0x70736433; /* 'psd3' */
531
532 /**
533 * ICC Profile Tag Signature: 'ps2s'.
534 */
535 public static final int icSigPs2CSATag = 0x70733273; /* 'ps2s' */
536
537 /**
538 * ICC Profile Tag Signature: 'ps2i'.
539 */
540 public static final int icSigPs2RenderingIntentTag = 0x70733269;
541 /* 'ps2i' */
542
543 /**
544 * ICC Profile Tag Signature: 'rXYZ'.
545 */
546 public static final int icSigRedColorantTag = 0x7258595A; /* 'rXYZ' */
547
548 /**
549 * ICC Profile Tag Signature: 'rXYZ'.
550 * @since 1.5
551 */
552 public static final int icSigRedMatrixColumnTag = 0x7258595A; /* 'rXYZ' */
553
554 /**
555 * ICC Profile Tag Signature: 'rTRC'.
556 */
557 public static final int icSigRedTRCTag = 0x72545243; /* 'rTRC' */
558
559 /**
560 * ICC Profile Tag Signature: 'scrd'.
561 */
562 public static final int icSigScreeningDescTag = 0x73637264; /* 'scrd' */
563
564 /**
565 * ICC Profile Tag Signature: 'scrn'.
566 */
567 public static final int icSigScreeningTag = 0x7363726E; /* 'scrn' */
568
569 /**
570 * ICC Profile Tag Signature: 'tech'.
571 */
572 public static final int icSigTechnologyTag = 0x74656368; /* 'tech' */
573
574 /**
575 * ICC Profile Tag Signature: 'bfd '.
576 */
577 public static final int icSigUcrBgTag = 0x62666420; /* 'bfd ' */
578
579 /**
580 * ICC Profile Tag Signature: 'vued'.
581 */
582 public static final int icSigViewingCondDescTag = 0x76756564; /* 'vued' */
583
584 /**
585 * ICC Profile Tag Signature: 'view'.
586 */
587 public static final int icSigViewingConditionsTag = 0x76696577;/* 'view' */
588
589 /**
590 * ICC Profile Tag Signature: 'chrm'.
591 */
592 public static final int icSigChromaticityTag = 0x6368726d; /* 'chrm' */
593
594 /**
595 * ICC Profile Tag Signature: 'chad'.
596 * @since 1.5
597 */
598 public static final int icSigChromaticAdaptationTag = 0x63686164;/* 'chad' */
599
600 /**
601 * ICC Profile Tag Signature: 'clro'.
602 * @since 1.5
603 */
604 public static final int icSigColorantOrderTag = 0x636C726F; /* 'clro' */
605
606 /**
607 * ICC Profile Tag Signature: 'clrt'.
608 * @since 1.5
609 */
610 public static final int icSigColorantTableTag = 0x636C7274; /* 'clrt' */
611
612
613 /**
614 * ICC Profile Header Location: profile size in bytes.
615 */
616 public static final int icHdrSize = 0; /* Profile size in bytes */
617
618 /**
619 * ICC Profile Header Location: CMM for this profile.
620 */
621 public static final int icHdrCmmId = 4; /* CMM for this profile */
622
623 /**
624 * ICC Profile Header Location: format version number.
625 */
626 public static final int icHdrVersion = 8; /* Format version number */
627
628 /**
629 * ICC Profile Header Location: type of profile.
630 */
631 public static final int icHdrDeviceClass = 12; /* Type of profile */
632
633 /**
634 * ICC Profile Header Location: color space of data.
635 */
636 public static final int icHdrColorSpace = 16; /* Color space of data */
637
638 /**
639 * ICC Profile Header Location: PCS - XYZ or Lab only.
640 */
641 public static final int icHdrPcs = 20; /* PCS - XYZ or Lab only */
642
643 /**
644 * ICC Profile Header Location: date profile was created.
645 */
646 public static final int icHdrDate = 24; /* Date profile was created */
647
648 /**
649 * ICC Profile Header Location: icMagicNumber.
650 */
651 public static final int icHdrMagic = 36; /* icMagicNumber */
652
653 /**
654 * ICC Profile Header Location: primary platform.
655 */
656 public static final int icHdrPlatform = 40; /* Primary Platform */
657
658 /**
659 * ICC Profile Header Location: various bit settings.
660 */
661 public static final int icHdrFlags = 44; /* Various bit settings */
662
663 /**
664 * ICC Profile Header Location: device manufacturer.
665 */
666 public static final int icHdrManufacturer = 48; /* Device manufacturer */
667
668 /**
669 * ICC Profile Header Location: device model number.
670 */
671 public static final int icHdrModel = 52; /* Device model number */
672
673 /**
674 * ICC Profile Header Location: device attributes.
675 */
676 public static final int icHdrAttributes = 56; /* Device attributes */
677
678 /**
679 * ICC Profile Header Location: rendering intent.
680 */
681 public static final int icHdrRenderingIntent = 64; /* Rendering intent */
682
683 /**
684 * ICC Profile Header Location: profile illuminant.
685 */
686 public static final int icHdrIlluminant = 68; /* Profile illuminant */
687
688 /**
689 * ICC Profile Header Location: profile creator.
690 */
691 public static final int icHdrCreator = 80; /* Profile creator */
692
693 /**
694 * ICC Profile Header Location: profile's ID.
695 * @since 1.5
696 */
697 public static final int icHdrProfileID = 84; /* Profile's ID */
698
699
700 /**
701 * ICC Profile Constant: tag type signaturE.
702 */
703 public static final int icTagType = 0; /* tag type signature */
704
705 /**
706 * ICC Profile Constant: reserved.
707 */
708 public static final int icTagReserved = 4; /* reserved */
709
710 /**
711 * ICC Profile Constant: curveType count.
712 */
713 public static final int icCurveCount = 8; /* curveType count */
714
715 /**
716 * ICC Profile Constant: curveType data.
717 */
718 public static final int icCurveData = 12; /* curveType data */
719
720 /**
721 * ICC Profile Constant: XYZNumber X.
722 */
723 public static final int icXYZNumberX = 8; /* XYZNumber X */
724
725
726 /**
727 * Constructs an ICC_Profile object with a given ID.
728 */
729 ICC_Profile(long ID) {
730 this.ID = ID;
731 }
732
733
734 /**
735 * Constructs an ICC_Profile object whose loading will be deferred.
736 * The ID will be 0 until the profile is loaded.
737 */
738 ICC_Profile(ProfileDeferralInfo pdi) {
739 this.deferralInfo = pdi;
740 this.profileActivator = new ProfileActivator() {
741 public void activate() throws ProfileDataException {
742 activateDeferredProfile();
743 }
744 };
745 ProfileDeferralMgr.registerDeferral(this.profileActivator);
746 }
747
748
749 /**
750 * Frees the resources associated with an ICC_Profile object.
751 */
752 protected void finalize () {
753 if (ID != 0) {
754 CMSManager.getModule().freeProfile(ID);
755 } else if (profileActivator != null) {
756 ProfileDeferralMgr.unregisterDeferral(profileActivator);
757 }
758 }
759
760
761 /**
762 * Constructs an ICC_Profile object corresponding to the data in
763 * a byte array. Throws an IllegalArgumentException if the data
764 * does not correspond to a valid ICC Profile.
765 * @param data the specified ICC Profile data
766 * @return an <code>ICC_Profile</code> object corresponding to
767 * the data in the specified <code>data</code> array.
768 */
769 public static ICC_Profile getInstance(byte[] data) {
770 ICC_Profile thisProfile;
771
772 long theID;
773
774 if (ProfileDeferralMgr.deferring) {
775 ProfileDeferralMgr.activateProfiles();
776 }
777
778 try {
779 theID = CMSManager.getModule().loadProfile(data);
780 } catch (CMMException c) {
781 throw new IllegalArgumentException("Invalid ICC Profile Data");
782 }
783
784 try {
785 if ((getColorSpaceType (theID) == ColorSpace.TYPE_GRAY) &&
786 (getData (theID, icSigMediaWhitePointTag) != null) &&
787 (getData (theID, icSigGrayTRCTag) != null)) {
788 thisProfile = new ICC_ProfileGray (theID);
789 }
790 else if ((getColorSpaceType (theID) == ColorSpace.TYPE_RGB) &&
791 (getData (theID, icSigMediaWhitePointTag) != null) &&
792 (getData (theID, icSigRedColorantTag) != null) &&
793 (getData (theID, icSigGreenColorantTag) != null) &&
794 (getData (theID, icSigBlueColorantTag) != null) &&
795 (getData (theID, icSigRedTRCTag) != null) &&
796 (getData (theID, icSigGreenTRCTag) != null) &&
797 (getData (theID, icSigBlueTRCTag) != null)) {
798 thisProfile = new ICC_ProfileRGB (theID);
799 }
800 else {
801 thisProfile = new ICC_Profile (theID);
802 }
803 } catch (CMMException c) {
804 thisProfile = new ICC_Profile (theID);
805 }
806 return thisProfile;
807 }
808
809
810
811 /**
812 * Constructs an ICC_Profile corresponding to one of the specific color
813 * spaces defined by the ColorSpace class (for example CS_sRGB).
814 * Throws an IllegalArgumentException if cspace is not one of the
815 * defined color spaces.
816 *
817 * @param cspace the type of color space to create a profile for.
818 * The specified type is one of the color
819 * space constants defined in the <CODE>ColorSpace</CODE> class.
820 *
821 * @return an <code>ICC_Profile</code> object corresponding to
822 * the specified <code>ColorSpace</code> type.
823 * @exception IllegalArgumentException If <CODE>cspace</CODE> is not
824 * one of the predefined color space types.
825 */
826 public static ICC_Profile getInstance (int cspace) {
827 ICC_Profile thisProfile = null;
828 String fileName;
829
830 switch (cspace) {
831 case ColorSpace.CS_sRGB:
832 synchronized(ICC_Profile.class) {
833 if (sRGBprofile == null) {
834 /*
835 * Deferral is only used for standard profiles.
836 * Enabling the appropriate access privileges is handled
837 * at a lower level.
838 */
839 ProfileDeferralInfo pInfo =
840 new ProfileDeferralInfo("sRGB.pf",
841 ColorSpace.TYPE_RGB, 3,
842 CLASS_DISPLAY);
843 sRGBprofile = getDeferredInstance(pInfo);
844 }
845 thisProfile = sRGBprofile;
846 }
847
848 break;
849
850 case ColorSpace.CS_CIEXYZ:
851 synchronized(ICC_Profile.class) {
852 if (XYZprofile == null) {
853 ProfileDeferralInfo pInfo =
854 new ProfileDeferralInfo("CIEXYZ.pf",
855 ColorSpace.TYPE_XYZ, 3,
856 CLASS_DISPLAY);
857 XYZprofile = getDeferredInstance(pInfo);
858 }
859 thisProfile = XYZprofile;
860 }
861
862 break;
863
864 case ColorSpace.CS_PYCC:
865 synchronized(ICC_Profile.class) {
866 if (PYCCprofile == null) {
867 if (standardProfileExists("PYCC.pf"))
868 {
869 ProfileDeferralInfo pInfo =
870 new ProfileDeferralInfo("PYCC.pf",
871 ColorSpace.TYPE_3CLR, 3,
872 CLASS_DISPLAY);
873 PYCCprofile = getDeferredInstance(pInfo);
874 } else {
875 throw new IllegalArgumentException(
876 "Can't load standard profile: PYCC.pf");
877 }
878 }
879 thisProfile = PYCCprofile;
880 }
881
882 break;
883
884 case ColorSpace.CS_GRAY:
885 synchronized(ICC_Profile.class) {
886 if (GRAYprofile == null) {
887 ProfileDeferralInfo pInfo =
888 new ProfileDeferralInfo("GRAY.pf",
889 ColorSpace.TYPE_GRAY, 1,
890 CLASS_DISPLAY);
891 GRAYprofile = getDeferredInstance(pInfo);
892 }
893 thisProfile = GRAYprofile;
894 }
895
896 break;
897
898 case ColorSpace.CS_LINEAR_RGB:
899 synchronized(ICC_Profile.class) {
900 if (LINEAR_RGBprofile == null) {
901 ProfileDeferralInfo pInfo =
902 new ProfileDeferralInfo("LINEAR_RGB.pf",
903 ColorSpace.TYPE_RGB, 3,
904 CLASS_DISPLAY);
905 LINEAR_RGBprofile = getDeferredInstance(pInfo);
906 }
907 thisProfile = LINEAR_RGBprofile;
908 }
909
910 break;
911
912 default:
913 throw new IllegalArgumentException("Unknown color space");
914 }
915
916 return thisProfile;
917 }
918
919 /* This asserts system privileges, so is used only for the
920 * standard profiles.
921 */
922 private static ICC_Profile getStandardProfile(final String name) {
923
924 return (ICC_Profile) AccessController.doPrivileged(
925 new PrivilegedAction() {
926 public Object run() {
927 ICC_Profile p = null;
928 try {
929 p = getInstance (name);
930 } catch (IOException ex) {
931 throw new IllegalArgumentException(
932 "Can't load standard profile: " + name);
933 }
934 return p;
935 }
936 });
937 }
938
939 /**
940 * Constructs an ICC_Profile corresponding to the data in a file.
941 * fileName may be an absolute or a relative file specification.
942 * Relative file names are looked for in several places: first, relative
943 * to any directories specified by the java.iccprofile.path property;
944 * second, relative to any directories specified by the java.class.path
945 * property; finally, in a directory used to store profiles always
946 * available, such as the profile for sRGB. Built-in profiles use .pf as
947 * the file name extension for profiles, e.g. sRGB.pf.
948 * This method throws an IOException if the specified file cannot be
949 * opened or if an I/O error occurs while reading the file. It throws
950 * an IllegalArgumentException if the file does not contain valid ICC
951 * Profile data.
952 * @param fileName The file that contains the data for the profile.
953 *
954 * @return an <code>ICC_Profile</code> object corresponding to
955 * the data in the specified file.
956 * @exception IOException If the specified file cannot be opened or
957 * an I/O error occurs while reading the file.
958 *
959 * @exception IllegalArgumentException If the file does not
960 * contain valid ICC Profile data.
961 *
962 * @exception SecurityException If a security manager is installed
963 * and it does not permit read access to the given file.
964 */
965 public static ICC_Profile getInstance(String fileName) throws IOException {
966 ICC_Profile thisProfile;
967 FileInputStream fis = null;
968
969
970 File f = getProfileFile(fileName);
971 if (f != null) {
972 fis = new FileInputStream(f);
973 }
974 if (fis == null) {
975 throw new IOException("Cannot open file " + fileName);
976 }
977
978 thisProfile = getInstance(fis);
979
980 fis.close(); /* close the file */
981
982 return thisProfile;
983 }
984
985
986 /**
987 * Constructs an ICC_Profile corresponding to the data in an InputStream.
988 * This method throws an IllegalArgumentException if the stream does not
989 * contain valid ICC Profile data. It throws an IOException if an I/O
990 * error occurs while reading the stream.
991 * @param s The input stream from which to read the profile data.
992 *
993 * @return an <CODE>ICC_Profile</CODE> object corresponding to the
994 * data in the specified <code>InputStream</code>.
995 *
996 * @exception IOException If an I/O error occurs while reading the stream.
997 *
998 * @exception IllegalArgumentException If the stream does not
999 * contain valid ICC Profile data.
1000 */
1001 public static ICC_Profile getInstance(InputStream s) throws IOException {
1002 byte profileData[];
1003
1004 if (s instanceof ProfileDeferralInfo) {
1005 /* hack to detect profiles whose loading can be deferred */
1006 return getDeferredInstance((ProfileDeferralInfo) s);
1007 }
1008
1009 if ((profileData = getProfileDataFromStream(s)) == null) {
1010 throw new IllegalArgumentException("Invalid ICC Profile Data");
1011 }
1012
1013 return getInstance(profileData);
1014 }
1015
1016
1017 static byte[] getProfileDataFromStream(InputStream s) throws IOException {
1018 byte profileData[];
1019 int profileSize;
1020
1021 byte header[] = new byte[128];
1022 int bytestoread = 128;
1023 int bytesread = 0;
1024 int n;
1025
1026 while (bytestoread != 0) {
1027 if ((n = s.read(header, bytesread, bytestoread)) < 0) {
1028 return null;
1029 }
1030 bytesread += n;
1031 bytestoread -= n;
1032 }
1033 if (header[36] != 0x61 || header[37] != 0x63 ||
1034 header[38] != 0x73 || header[39] != 0x70) {
1035 return null; /* not a valid profile */
1036 }
1037 profileSize = ((header[0] & 0xff) << 24) |
1038 ((header[1] & 0xff) << 16) |
1039 ((header[2] & 0xff) << 8) |
1040 (header[3] & 0xff);
1041 profileData = new byte[profileSize];
1042 System.arraycopy(header, 0, profileData, 0, 128);
1043 bytestoread = profileSize - 128;
1044 bytesread = 128;
1045 while (bytestoread != 0) {
1046 if ((n = s.read(profileData, bytesread, bytestoread)) < 0) {
1047 return null;
1048 }
1049 bytesread += n;
1050 bytestoread -= n;
1051 }
1052
1053 return profileData;
1054 }
1055
1056
1057 /**
1058 * Constructs an ICC_Profile for which the actual loading of the
1059 * profile data from a file and the initialization of the CMM should
1060 * be deferred as long as possible.
1061 * Deferral is only used for standard profiles.
1062 * If deferring is disabled, then getStandardProfile() ensures
1063 * that all of the appropriate access privileges are granted
1064 * when loading this profile.
1065 * If deferring is enabled, then the deferred activation
1066 * code will take care of access privileges.
1067 * @see activateDeferredProfile()
1068 */
1069 static ICC_Profile getDeferredInstance(ProfileDeferralInfo pdi) {
1070 if (!ProfileDeferralMgr.deferring) {
1071 return getStandardProfile(pdi.filename);
1072 }
1073 if (pdi.colorSpaceType == ColorSpace.TYPE_RGB) {
1074 return new ICC_ProfileRGB(pdi);
1075 } else if (pdi.colorSpaceType == ColorSpace.TYPE_GRAY) {
1076 return new ICC_ProfileGray(pdi);
1077 } else {
1078 return new ICC_Profile(pdi);
1079 }
1080 }
1081
1082
1083 void activateDeferredProfile() throws ProfileDataException {
1084 byte profileData[];
1085 FileInputStream fis;
1086 final String fileName = deferralInfo.filename;
1087
1088 profileActivator = null;
1089 deferralInfo = null;
1090 PrivilegedAction<FileInputStream> pa = new PrivilegedAction<FileInputStream>() {
1091 public FileInputStream run() {
1092 File f = getStandardProfileFile(fileName);
1093 if (f != null) {
1094 try {
1095 return new FileInputStream(f);
1096 } catch (FileNotFoundException e) {}
1097 }
1098 return null;
1099 }
1100 };
1101 if ((fis = AccessController.doPrivileged(pa)) == null) {
1102 throw new ProfileDataException("Cannot open file " + fileName);
1103 }
1104 try {
1105 profileData = getProfileDataFromStream(fis);
1106 fis.close(); /* close the file */
1107 }
1108 catch (IOException e) {
1109 ProfileDataException pde = new
1110 ProfileDataException("Invalid ICC Profile Data" + fileName);
1111 pde.initCause(e);
1112 throw pde;
1113 }
1114 if (profileData == null) {
1115 throw new ProfileDataException("Invalid ICC Profile Data" +
1116 fileName);
1117 }
1118 try {
1119 ID = CMSManager.getModule().loadProfile(profileData);
1120 } catch (CMMException c) {
1121 ProfileDataException pde = new
1122 ProfileDataException("Invalid ICC Profile Data" + fileName);
1123 pde.initCause(c);
1124 throw pde;
1125 }
1126 }
1127
1128
1129 /**
1130 * Returns profile major version.
1131 * @return The major version of the profile.
1132 */
1133 public int getMajorVersion() {
1134 byte[] theHeader;
1135
1136 theHeader = getData(icSigHead); /* getData will activate deferred
1137 profiles if necessary */
1138
1139 return (int) theHeader[8];
1140 }
1141
1142 /**
1143 * Returns profile minor version.
1144 * @return The minor version of the profile.
1145 */
1146 public int getMinorVersion() {
1147 byte[] theHeader;
1148
1149 theHeader = getData(icSigHead); /* getData will activate deferred
1150 profiles if necessary */
1151
1152 return (int) theHeader[9];
1153 }
1154
1155 /**
1156 * Returns the profile class.
1157 * @return One of the predefined profile class constants.
1158 */
1159 public int getProfileClass() {
1160 byte[] theHeader;
1161 int theClassSig, theClass;
1162
1163 if (deferralInfo != null) {
1164 return deferralInfo.profileClass; /* Need to have this info for
1165 ICC_ColorSpace without
1166 causing a deferred profile
1167 to be loaded */
1168 }
1169
1170 theHeader = getData(icSigHead);
1171
1172 theClassSig = intFromBigEndian (theHeader, icHdrDeviceClass);
1173
1174 switch (theClassSig) {
1175 case icSigInputClass:
1176 theClass = CLASS_INPUT;
1177 break;
1178
1179 case icSigDisplayClass:
1180 theClass = CLASS_DISPLAY;
1181 break;
1182
1183 case icSigOutputClass:
1184 theClass = CLASS_OUTPUT;
1185 break;
1186
1187 case icSigLinkClass:
1188 theClass = CLASS_DEVICELINK;
1189 break;
1190
1191 case icSigColorSpaceClass:
1192 theClass = CLASS_COLORSPACECONVERSION;
1193 break;
1194
1195 case icSigAbstractClass:
1196 theClass = CLASS_ABSTRACT;
1197 break;
1198
1199 case icSigNamedColorClass:
1200 theClass = CLASS_NAMEDCOLOR;
1201 break;
1202
1203 default:
1204 throw new IllegalArgumentException("Unknown profile class");
1205 }
1206
1207 return theClass;
1208 }
1209
1210 /**
1211 * Returns the color space type. Returns one of the color space type
1212 * constants defined by the ColorSpace class. This is the
1213 * "input" color space of the profile. The type defines the
1214 * number of components of the color space and the interpretation,
1215 * e.g. TYPE_RGB identifies a color space with three components - red,
1216 * green, and blue. It does not define the particular color
1217 * characteristics of the space, e.g. the chromaticities of the
1218 * primaries.
1219 * @return One of the color space type constants defined in the
1220 * <CODE>ColorSpace</CODE> class.
1221 */
1222 public int getColorSpaceType() {
1223 if (deferralInfo != null) {
1224 return deferralInfo.colorSpaceType; /* Need to have this info for
1225 ICC_ColorSpace without
1226 causing a deferred profile
1227 to be loaded */
1228 }
1229 return getColorSpaceType(ID);
1230 }
1231
1232 static int getColorSpaceType(long profileID) {
1233 byte[] theHeader;
1234 int theColorSpaceSig, theColorSpace;
1235
1236 theHeader = getData(profileID, icSigHead);
1237 theColorSpaceSig = intFromBigEndian(theHeader, icHdrColorSpace);
1238 theColorSpace = iccCStoJCS (theColorSpaceSig);
1239 return theColorSpace;
1240 }
1241
1242 /**
1243 * Returns the color space type of the Profile Connection Space (PCS).
1244 * Returns one of the color space type constants defined by the
1245 * ColorSpace class. This is the "output" color space of the
1246 * profile. For an input, display, or output profile useful
1247 * for tagging colors or images, this will be either TYPE_XYZ or
1248 * TYPE_Lab and should be interpreted as the corresponding specific
1249 * color space defined in the ICC specification. For a device
1250 * link profile, this could be any of the color space type constants.
1251 * @return One of the color space type constants defined in the
1252 * <CODE>ColorSpace</CODE> class.
1253 */
1254 public int getPCSType() {
1255 if (ProfileDeferralMgr.deferring) {
1256 ProfileDeferralMgr.activateProfiles();
1257 }
1258 return getPCSType(ID);
1259 }
1260
1261
1262 static int getPCSType(long profileID) {
1263 byte[] theHeader;
1264 int thePCSSig, thePCS;
1265
1266 theHeader = getData(profileID, icSigHead);
1267 thePCSSig = intFromBigEndian(theHeader, icHdrPcs);
1268 thePCS = iccCStoJCS(thePCSSig);
1269 return thePCS;
1270 }
1271
1272
1273 /**
1274 * Write this ICC_Profile to a file.
1275 *
1276 * @param fileName The file to write the profile data to.
1277 *
1278 * @exception IOException If the file cannot be opened for writing
1279 * or an I/O error occurs while writing to the file.
1280 */
1281 public void write(String fileName) throws IOException {
1282 FileOutputStream outputFile;
1283 byte profileData[];
1284
1285 profileData = getData(); /* this will activate deferred
1286 profiles if necessary */
1287 outputFile = new FileOutputStream(fileName);
1288 outputFile.write(profileData);
1289 outputFile.close ();
1290 }
1291
1292
1293 /**
1294 * Write this ICC_Profile to an OutputStream.
1295 *
1296 * @param s The stream to write the profile data to.
1297 *
1298 * @exception IOException If an I/O error occurs while writing to the
1299 * stream.
1300 */
1301 public void write(OutputStream s) throws IOException {
1302 byte profileData[];
1303
1304 profileData = getData(); /* this will activate deferred
1305 profiles if necessary */
1306 s.write(profileData);
1307 }
1308
1309
1310 /**
1311 * Returns a byte array corresponding to the data of this ICC_Profile.
1312 * @return A byte array that contains the profile data.
1313 * @see #setData(int, byte[])
1314 */
1315 public byte[] getData() {
1316 int profileSize;
1317 byte[] profileData;
1318
1319 if (ProfileDeferralMgr.deferring) {
1320 ProfileDeferralMgr.activateProfiles();
1321 }
1322
1323 PCMM mdl = CMSManager.getModule();
1324
1325 /* get the number of bytes needed for this profile */
1326 profileSize = mdl.getProfileSize(ID);
1327
1328 profileData = new byte [profileSize];
1329
1330 /* get the data for the profile */
1331 mdl.getProfileData(ID, profileData);
1332
1333 return profileData;
1334 }
1335
1336
1337 /**
1338 * Returns a particular tagged data element from the profile as
1339 * a byte array. Elements are identified by signatures
1340 * as defined in the ICC specification. The signature
1341 * icSigHead can be used to get the header. This method is useful
1342 * for advanced applets or applications which need to access
1343 * profile data directly.
1344 *
1345 * @param tagSignature The ICC tag signature for the data element you
1346 * want to get.
1347 *
1348 * @return A byte array that contains the tagged data element. Returns
1349 * <code>null</code> if the specified tag doesn't exist.
1350 * @see #setData(int, byte[])
1351 */
1352 public byte[] getData(int tagSignature) {
1353
1354 if (ProfileDeferralMgr.deferring) {
1355 ProfileDeferralMgr.activateProfiles();
1356 }
1357
1358 return getData(ID, tagSignature);
1359 }
1360
1361
1362 static byte[] getData(long profileID, int tagSignature) {
1363 int tagSize;
1364 byte[] tagData;
1365
1366 try {
1367 PCMM mdl = CMSManager.getModule();
1368
1369 /* get the number of bytes needed for this tag */
1370 tagSize = mdl.getTagSize(profileID, tagSignature);
1371
1372 tagData = new byte[tagSize]; /* get an array for the tag */
1373
1374 /* get the tag's data */
1375 mdl.getTagData(profileID, tagSignature, tagData);
1376 } catch(CMMException c) {
1377 tagData = null;
1378 }
1379
1380 return tagData;
1381 }
1382
1383 /**
1384 * Sets a particular tagged data element in the profile from
1385 * a byte array. The array should contain data in a format, corresponded
1386 * to the {@code tagSignature} as defined in the ICC specification, section 10.
1387 * This method is useful for advanced applets or applications which need to
1388 * access profile data directly.
1389 *
1390 * @param tagSignature The ICC tag signature for the data element
1391 * you want to set.
1392 * @param tagData the data to set for the specified tag signature
1393 * @throws IllegalArgumentException if {@code tagSignature} is not a signature
1394 * as defined in the ICC specification.
1395 * @throws IllegalArgumentException if a content of the {@code tagData}
1396 * array can not be interpreted as valid tag data, corresponding
1397 * to the {@code tagSignature}.
1398 * @see #getData
1399 */
1400 public void setData(int tagSignature, byte[] tagData) {
1401
1402 if (ProfileDeferralMgr.deferring) {
1403 ProfileDeferralMgr.activateProfiles();
1404 }
1405
1406 CMSManager.getModule().setTagData(ID, tagSignature, tagData);
1407 }
1408
1409 /**
1410 * Sets the rendering intent of the profile.
1411 * This is used to select the proper transform from a profile that
1412 * has multiple transforms.
1413 */
1414 void setRenderingIntent(int renderingIntent) {
1415 byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1416 profiles if necessary */
1417 intToBigEndian (renderingIntent, theHeader, icHdrRenderingIntent);
1418 /* set the rendering intent */
1419 setData (icSigHead, theHeader);
1420 }
1421
1422
1423 /**
1424 * Returns the rendering intent of the profile.
1425 * This is used to select the proper transform from a profile that
1426 * has multiple transforms. It is typically set in a source profile
1427 * to select a transform from an output profile.
1428 */
1429 int getRenderingIntent() {
1430 byte[] theHeader = getData(icSigHead);/* getData will activate deferred
1431 profiles if necessary */
1432
1433 int renderingIntent = intFromBigEndian(theHeader, icHdrRenderingIntent);
1434 /* set the rendering intent */
1435 return renderingIntent;
1436 }
1437
1438
1439 /**
1440 * Returns the number of color components in the "input" color
1441 * space of this profile. For example if the color space type
1442 * of this profile is TYPE_RGB, then this method will return 3.
1443 *
1444 * @return The number of color components in the profile's input
1445 * color space.
1446 *
1447 * @throws ProfileDataException if color space is in the profile
1448 * is invalid
1449 */
1450 public int getNumComponents() {
1451 byte[] theHeader;
1452 int theColorSpaceSig, theNumComponents;
1453
1454 if (deferralInfo != null) {
1455 return deferralInfo.numComponents; /* Need to have this info for
1456 ICC_ColorSpace without
1457 causing a deferred profile
1458 to be loaded */
1459 }
1460 theHeader = getData(icSigHead);
1461
1462 theColorSpaceSig = intFromBigEndian (theHeader, icHdrColorSpace);
1463
1464 switch (theColorSpaceSig) {
1465 case icSigGrayData:
1466 theNumComponents = 1;
1467 break;
1468
1469 case icSigSpace2CLR:
1470 theNumComponents = 2;
1471 break;
1472
1473 case icSigXYZData:
1474 case icSigLabData:
1475 case icSigLuvData:
1476 case icSigYCbCrData:
1477 case icSigYxyData:
1478 case icSigRgbData:
1479 case icSigHsvData:
1480 case icSigHlsData:
1481 case icSigCmyData:
1482 case icSigSpace3CLR:
1483 theNumComponents = 3;
1484 break;
1485
1486 case icSigCmykData:
1487 case icSigSpace4CLR:
1488 theNumComponents = 4;
1489 break;
1490
1491 case icSigSpace5CLR:
1492 theNumComponents = 5;
1493 break;
1494
1495 case icSigSpace6CLR:
1496 theNumComponents = 6;
1497 break;
1498
1499 case icSigSpace7CLR:
1500 theNumComponents = 7;
1501 break;
1502
1503 case icSigSpace8CLR:
1504 theNumComponents = 8;
1505 break;
1506
1507 case icSigSpace9CLR:
1508 theNumComponents = 9;
1509 break;
1510
1511 case icSigSpaceACLR:
1512 theNumComponents = 10;
1513 break;
1514
1515 case icSigSpaceBCLR:
1516 theNumComponents = 11;
1517 break;
1518
1519 case icSigSpaceCCLR:
1520 theNumComponents = 12;
1521 break;
1522
1523 case icSigSpaceDCLR:
1524 theNumComponents = 13;
1525 break;
1526
1527 case icSigSpaceECLR:
1528 theNumComponents = 14;
1529 break;
1530
1531 case icSigSpaceFCLR:
1532 theNumComponents = 15;
1533 break;
1534
1535 default:
1536 throw new ProfileDataException ("invalid ICC color space");
1537 }
1538
1539 return theNumComponents;
1540 }
1541
1542
1543 /**
1544 * Returns a float array of length 3 containing the X, Y, and Z
1545 * components of the mediaWhitePointTag in the ICC profile.
1546 */
1547 float[] getMediaWhitePoint() {
1548 return getXYZTag(icSigMediaWhitePointTag);
1549 /* get the media white point tag */
1550 }
1551
1552
1553 /**
1554 * Returns a float array of length 3 containing the X, Y, and Z
1555 * components encoded in an XYZType tag.
1556 */
1557 float[] getXYZTag(int theTagSignature) {
1558 byte[] theData;
1559 float[] theXYZNumber;
1560 int i1, i2, theS15Fixed16;
1561
1562 theData = getData(theTagSignature); /* get the tag data */
1563 /* getData will activate deferred
1564 profiles if necessary */
1565
1566 theXYZNumber = new float [3]; /* array to return */
1567
1568 /* convert s15Fixed16Number to float */
1569 for (i1 = 0, i2 = icXYZNumberX; i1 < 3; i1++, i2 += 4) {
1570 theS15Fixed16 = intFromBigEndian(theData, i2);
1571 theXYZNumber [i1] = ((float) theS15Fixed16) / 65536.0f;
1572 }
1573 return theXYZNumber;
1574 }
1575
1576
1577 /**
1578 * Returns a gamma value representing a tone reproduction
1579 * curve (TRC). If the profile represents the TRC as a table rather
1580 * than a single gamma value, then an exception is thrown. In this
1581 * case the actual table can be obtained via getTRC().
1582 * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1583 * icSigGreenTRCTag, or icSigBlueTRCTag.
1584 * @return the gamma value as a float.
1585 * @exception ProfileDataException if the profile does not specify
1586 * the TRC as a single gamma value.
1587 */
1588 float getGamma(int theTagSignature) {
1589 byte[] theTRCData;
1590 float theGamma;
1591 int theU8Fixed8;
1592
1593 theTRCData = getData(theTagSignature); /* get the TRC */
1594 /* getData will activate deferred
1595 profiles if necessary */
1596
1597 if (intFromBigEndian (theTRCData, icCurveCount) != 1) {
1598 throw new ProfileDataException ("TRC is not a gamma");
1599 }
1600
1601 /* convert u8Fixed8 to float */
1602 theU8Fixed8 = (shortFromBigEndian(theTRCData, icCurveData)) & 0xffff;
1603
1604 theGamma = ((float) theU8Fixed8) / 256.0f;
1605
1606 return theGamma;
1607 }
1608
1609
1610 /**
1611 * Returns the TRC as an array of shorts. If the profile has
1612 * specified the TRC as linear (gamma = 1.0) or as a simple gamma
1613 * value, this method throws an exception, and the getGamma() method
1614 * should be used to get the gamma value. Otherwise the short array
1615 * returned here represents a lookup table where the input Gray value
1616 * is conceptually in the range [0.0, 1.0]. Value 0.0 maps
1617 * to array index 0 and value 1.0 maps to array index length-1.
1618 * Interpolation may be used to generate output values for
1619 * input values which do not map exactly to an index in the
1620 * array. Output values also map linearly to the range [0.0, 1.0].
1621 * Value 0.0 is represented by an array value of 0x0000 and
1622 * value 1.0 by 0xFFFF, i.e. the values are really unsigned
1623 * short values, although they are returned in a short array.
1624 * theTagSignature should be one of icSigGrayTRCTag, icSigRedTRCTag,
1625 * icSigGreenTRCTag, or icSigBlueTRCTag.
1626 * @return a short array representing the TRC.
1627 * @exception ProfileDataException if the profile does not specify
1628 * the TRC as a table.
1629 */
1630 short[] getTRC(int theTagSignature) {
1631 byte[] theTRCData;
1632 short[] theTRC;
1633 int i1, i2, nElements, theU8Fixed8;
1634
1635 theTRCData = getData(theTagSignature); /* get the TRC */
1636 /* getData will activate deferred
1637 profiles if necessary */
1638
1639 nElements = intFromBigEndian(theTRCData, icCurveCount);
1640
1641 if (nElements == 1) {
1642 throw new ProfileDataException("TRC is not a table");
1643 }
1644
1645 /* make the short array */
1646 theTRC = new short [nElements];
1647
1648 for (i1 = 0, i2 = icCurveData; i1 < nElements; i1++, i2 += 2) {
1649 theTRC[i1] = shortFromBigEndian(theTRCData, i2);
1650 }
1651
1652 return theTRC;
1653 }
1654
1655
1656 /* convert an ICC color space signature into a Java color space type */
1657 static int iccCStoJCS(int theColorSpaceSig) {
1658 int theColorSpace;
1659
1660 switch (theColorSpaceSig) {
1661 case icSigXYZData:
1662 theColorSpace = ColorSpace.TYPE_XYZ;
1663 break;
1664
1665 case icSigLabData:
1666 theColorSpace = ColorSpace.TYPE_Lab;
1667 break;
1668
1669 case icSigLuvData:
1670 theColorSpace = ColorSpace.TYPE_Luv;
1671 break;
1672
1673 case icSigYCbCrData:
1674 theColorSpace = ColorSpace.TYPE_YCbCr;
1675 break;
1676
1677 case icSigYxyData:
1678 theColorSpace = ColorSpace.TYPE_Yxy;
1679 break;
1680
1681 case icSigRgbData:
1682 theColorSpace = ColorSpace.TYPE_RGB;
1683 break;
1684
1685 case icSigGrayData:
1686 theColorSpace = ColorSpace.TYPE_GRAY;
1687 break;
1688
1689 case icSigHsvData:
1690 theColorSpace = ColorSpace.TYPE_HSV;
1691 break;
1692
1693 case icSigHlsData:
1694 theColorSpace = ColorSpace.TYPE_HLS;
1695 break;
1696
1697 case icSigCmykData:
1698 theColorSpace = ColorSpace.TYPE_CMYK;
1699 break;
1700
1701 case icSigCmyData:
1702 theColorSpace = ColorSpace.TYPE_CMY;
1703 break;
1704
1705 case icSigSpace2CLR:
1706 theColorSpace = ColorSpace.TYPE_2CLR;
1707 break;
1708
1709 case icSigSpace3CLR:
1710 theColorSpace = ColorSpace.TYPE_3CLR;
1711 break;
1712
1713 case icSigSpace4CLR:
1714 theColorSpace = ColorSpace.TYPE_4CLR;
1715 break;
1716
1717 case icSigSpace5CLR:
1718 theColorSpace = ColorSpace.TYPE_5CLR;
1719 break;
1720
1721 case icSigSpace6CLR:
1722 theColorSpace = ColorSpace.TYPE_6CLR;
1723 break;
1724
1725 case icSigSpace7CLR:
1726 theColorSpace = ColorSpace.TYPE_7CLR;
1727 break;
1728
1729 case icSigSpace8CLR:
1730 theColorSpace = ColorSpace.TYPE_8CLR;
1731 break;
1732
1733 case icSigSpace9CLR:
1734 theColorSpace = ColorSpace.TYPE_9CLR;
1735 break;
1736
1737 case icSigSpaceACLR:
1738 theColorSpace = ColorSpace.TYPE_ACLR;
1739 break;
1740
1741 case icSigSpaceBCLR:
1742 theColorSpace = ColorSpace.TYPE_BCLR;
1743 break;
1744
1745 case icSigSpaceCCLR:
1746 theColorSpace = ColorSpace.TYPE_CCLR;
1747 break;
1748
1749 case icSigSpaceDCLR:
1750 theColorSpace = ColorSpace.TYPE_DCLR;
1751 break;
1752
1753 case icSigSpaceECLR:
1754 theColorSpace = ColorSpace.TYPE_ECLR;
1755 break;
1756
1757 case icSigSpaceFCLR:
1758 theColorSpace = ColorSpace.TYPE_FCLR;
1759 break;
1760
1761 default:
1762 throw new IllegalArgumentException ("Unknown color space");
1763 }
1764
1765 return theColorSpace;
1766 }
1767
1768
1769 static int intFromBigEndian(byte[] array, int index) {
1770 return (((array[index] & 0xff) << 24) |
1771 ((array[index+1] & 0xff) << 16) |
1772 ((array[index+2] & 0xff) << 8) |
1773 (array[index+3] & 0xff));
1774 }
1775
1776
1777 static void intToBigEndian(int value, byte[] array, int index) {
1778 array[index] = (byte) (value >> 24);
1779 array[index+1] = (byte) (value >> 16);
1780 array[index+2] = (byte) (value >> 8);
1781 array[index+3] = (byte) (value);
1782 }
1783
1784
1785 static short shortFromBigEndian(byte[] array, int index) {
1786 return (short) (((array[index] & 0xff) << 8) |
1787 (array[index+1] & 0xff));
1788 }
1789
1790
1791 static void shortToBigEndian(short value, byte[] array, int index) {
1792 array[index] = (byte) (value >> 8);
1793 array[index+1] = (byte) (value);
1794 }
1795
1796
1797 /*
1798 * fileName may be an absolute or a relative file specification.
1799 * Relative file names are looked for in several places: first, relative
1800 * to any directories specified by the java.iccprofile.path property;
1801 * second, relative to any directories specified by the java.class.path
1802 * property; finally, in a directory used to store profiles always
1803 * available, such as a profile for sRGB. Built-in profiles use .pf as
1804 * the file name extension for profiles, e.g. sRGB.pf.
1805 */
1806 private static File getProfileFile(String fileName) {
1807 String path, dir, fullPath;
1808
1809 File f = new File(fileName); /* try absolute file name */
1810 if (f.isAbsolute()) {
1811 /* Rest of code has little sense for an absolute pathname,
1812 so return here. */
1813 return f.isFile() ? f : null;
1814 }
1815 if ((!f.isFile()) &&
1816 ((path = System.getProperty("java.iccprofile.path")) != null)){
1817 /* try relative to java.iccprofile.path */
1818 StringTokenizer st =
1819 new StringTokenizer(path, File.pathSeparator);
1820 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1821 dir = st.nextToken();
1822 fullPath = dir + File.separatorChar + fileName;
1823 f = new File(fullPath);
1824 if (!isChildOf(f, dir)) {
1825 f = null;
1826 }
1827 }
1828 }
1829
1830 if (((f == null) || (!f.isFile())) &&
1831 ((path = System.getProperty("java.class.path")) != null)) {
1832 /* try relative to java.class.path */
1833 StringTokenizer st =
1834 new StringTokenizer(path, File.pathSeparator);
1835 while (st.hasMoreTokens() && ((f == null) || (!f.isFile()))) {
1836 dir = st.nextToken();
1837 fullPath = dir + File.separatorChar + fileName;
1838 f = new File(fullPath);
1839 }
1840 }
1841
1842 if ((f == null) || (!f.isFile())) {
1843 /* try the directory of built-in profiles */
1844 f = getStandardProfileFile(fileName);
1845 }
1846 if (f != null && f.isFile()) {
1847 return f;
1848 }
1849 return null;
1850 }
1851
1852 /**
1853 * Returns a file object corresponding to a built-in profile
1854 * specified by fileName.
1855 * If there is no built-in profile with such name, then the method
1856 * returns null.
1857 */
1858 private static File getStandardProfileFile(String fileName) {
1859 String dir = System.getProperty("java.home") +
1860 File.separatorChar + "lib" + File.separatorChar + "cmm";
1861 String fullPath = dir + File.separatorChar + fileName;
1862 File f = new File(fullPath);
1863 return (f.isFile() && isChildOf(f, dir)) ? f : null;
1864 }
1865
1866 /**
1867 * Checks whether given file resides inside give directory.
1868 */
1869 private static boolean isChildOf(File f, String dirName) {
1870 try {
1871 File dir = new File(dirName);
1872 String canonicalDirName = dir.getCanonicalPath();
1873 if (!canonicalDirName.endsWith(File.separator)) {
1874 canonicalDirName += File.separator;
1875 }
1876 String canonicalFileName = f.getCanonicalPath();
1877 return canonicalFileName.startsWith(canonicalDirName);
1878 } catch (IOException e) {
1879 /* we do not expect the IOException here, because invocation
1880 * of this function is always preceeded by isFile() call.
1881 */
1882 return false;
1883 }
1884 }
1885
1886 /**
1887 * Checks whether built-in profile specified by fileName exists.
1888 */
1889 private static boolean standardProfileExists(final String fileName) {
1890 return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
1891 public Boolean run() {
1892 return getStandardProfileFile(fileName) != null;
1893 }
1894 });
1895 }
1896
1897
1898 /*
1899 * Serialization support.
1900 *
1901 * Directly deserialized profiles are useless since they are not
1902 * registered with CMM. We don't allow constructor to be called
1903 * directly and instead have clients to call one of getInstance
1904 * factory methods that will register the profile with CMM. For
1905 * deserialization we implement readResolve method that will
1906 * resolve the bogus deserialized profile object with one obtained
1907 * with getInstance as well.
1908 *
1909 * There're two primary factory methods for construction of ICC
1910 * profiles: getInstance(int cspace) and getInstance(byte[] data).
1911 * This implementation of ICC_Profile uses the former to return a
1912 * cached singleton profile object, other implementations will
1913 * likely use this technique too. To preserve the singleton
1914 * pattern across serialization we serialize cached singleton
1915 * profiles in such a way that deserializing VM could call
1916 * getInstance(int cspace) method that will resolve deserialized
1917 * object into the corresponding singleton as well.
1918 *
1919 * Since the singletons are private to ICC_Profile the readResolve
1920 * method have to be `protected' instead of `private' so that
1921 * singletons that are instances of subclasses of ICC_Profile
1922 * could be correctly deserialized.
1923 */
1924
1925
1926 /**
1927 * Version of the format of additional serialized data in the
1928 * stream. Version <code>1</code> corresponds to Java 2
1929 * Platform, v1.3.
1930 * @since 1.3
1931 * @serial
1932 */
1933 private int iccProfileSerializedDataVersion = 1;
1934
1935
1936 /**
1937 * Writes default serializable fields to the stream. Writes a
1938 * string and an array of bytes to the stream as additional data.
1939 *
1940 * @param s stream used for serialization.
1941 * @throws IOException
1942 * thrown by <code>ObjectInputStream</code>.
1943 * @serialData
1944 * The <code>String</code> is the name of one of
1945 * <code>CS_<var>*</var></code> constants defined in the
1946 * {@link ColorSpace} class if the profile object is a profile
1947 * for a predefined color space (for example
1948 * <code>"CS_sRGB"</code>). The string is <code>null</code>
1949 * otherwise.
1950 * <p>
1951 * The <code>byte[]</code> array is the profile data for the
1952 * profile. For predefined color spaces <code>null</code> is
1953 * written instead of the profile data. If in the future
1954 * versions of Java API new predefined color spaces will be
1955 * added, future versions of this class may choose to write
1956 * for new predefined color spaces not only the color space
1957 * name, but the profile data as well so that older versions
1958 * could still deserialize the object.
1959 */
1960 private void writeObject(ObjectOutputStream s)
1961 throws IOException
1962 {
1963 s.defaultWriteObject();
1964
1965 String csName = null;
1966 if (this == sRGBprofile) {
1967 csName = "CS_sRGB";
1968 } else if (this == XYZprofile) {
1969 csName = "CS_CIEXYZ";
1970 } else if (this == PYCCprofile) {
1971 csName = "CS_PYCC";
1972 } else if (this == GRAYprofile) {
1973 csName = "CS_GRAY";
1974 } else if (this == LINEAR_RGBprofile) {
1975 csName = "CS_LINEAR_RGB";
1976 }
1977
1978 // Future versions may choose to write profile data for new
1979 // predefined color spaces as well, if any will be introduced,
1980 // so that old versions that don't recognize the new CS name
1981 // may fall back to constructing profile from the data.
1982 byte[] data = null;
1983 if (csName == null) {
1984 // getData will activate deferred profile if necessary
1985 data = getData();
1986 }
1987
1988 s.writeObject(csName);
1989 s.writeObject(data);
1990 }
1991
1992 // Temporary storage used by readObject to store resolved profile
1993 // (obtained with getInstance) for readResolve to return.
1994 private transient ICC_Profile resolvedDeserializedProfile;
1995
1996 /**
1997 * Reads default serializable fields from the stream. Reads from
1998 * the stream a string and an array of bytes as additional data.
1999 *
2000 * @param s stream used for deserialization.
2001 * @throws IOException
2002 * thrown by <code>ObjectInputStream</code>.
2003 * @throws ClassNotFoundException
2004 * thrown by <code>ObjectInputStream</code>.
2005 * @serialData
2006 * The <code>String</code> is the name of one of
2007 * <code>CS_<var>*</var></code> constants defined in the
2008 * {@link ColorSpace} class if the profile object is a profile
2009 * for a predefined color space (for example
2010 * <code>"CS_sRGB"</code>). The string is <code>null</code>
2011 * otherwise.
2012 * <p>
2013 * The <code>byte[]</code> array is the profile data for the
2014 * profile. It will usually be <code>null</code> for the
2015 * predefined profiles.
2016 * <p>
2017 * If the string is recognized as a constant name for
2018 * predefined color space the object will be resolved into
2019 * profile obtained with
2020 * <code>getInstance(int cspace)</code> and the profile
2021 * data are ignored. Otherwise the object will be resolved
2022 * into profile obtained with
2023 * <code>getInstance(byte[] data)</code>.
2024 * @see #readResolve()
2025 * @see #getInstance(int)
2026 * @see #getInstance(byte[])
2027 */
2028 private void readObject(ObjectInputStream s)
2029 throws IOException, ClassNotFoundException
2030 {
2031 s.defaultReadObject();
2032
2033 String csName = (String)s.readObject();
2034 byte[] data = (byte[])s.readObject();
2035
2036 int cspace = 0; // ColorSpace.CS_* constant if known
2037 boolean isKnownPredefinedCS = false;
2038 if (csName != null) {
2039 isKnownPredefinedCS = true;
2040 if (csName.equals("CS_sRGB")) {
2041 cspace = ColorSpace.CS_sRGB;
2042 } else if (csName.equals("CS_CIEXYZ")) {
2043 cspace = ColorSpace.CS_CIEXYZ;
2044 } else if (csName.equals("CS_PYCC")) {
2045 cspace = ColorSpace.CS_PYCC;
2046 } else if (csName.equals("CS_GRAY")) {
2047 cspace = ColorSpace.CS_GRAY;
2048 } else if (csName.equals("CS_LINEAR_RGB")) {
2049 cspace = ColorSpace.CS_LINEAR_RGB;
2050 } else {
2051 isKnownPredefinedCS = false;
2052 }
2053 }
2054
2055 if (isKnownPredefinedCS) {
2056 resolvedDeserializedProfile = getInstance(cspace);
2057 } else {
2058 resolvedDeserializedProfile = getInstance(data);
2059 }
2060 }
2061
2062 /**
2063 * Resolves instances being deserialized into instances registered
2064 * with CMM.
2065 * @return ICC_Profile object for profile registered with CMM.
2066 * @throws ObjectStreamException
2067 * never thrown, but mandated by the serialization spec.
2068 * @since 1.3
2069 */
2070 protected Object readResolve() throws ObjectStreamException {
2071 return resolvedDeserializedProfile;
2072 }
2073 }